	package storm.Processors;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Vector;

import storm.Tasks.Task;

/***********************************************/
public class LEATCacheMultitask extends Cache {
	Vector <storm.Tasks.Task>Tasks;
	String nameCP ;
	Memory memory;
	private PrintWriter outPutCartofile;
	private PrintWriter outPutLogFile;
	public Task Last_running = null;

	
	
	public LEATCacheMultitask (){
		super();
		this.Tasks = new Vector<Task>();
		 nameCP = this.toString()+"_CP";
	}

	
	public void setMemory(int s){
		 try {
			 if (this.getOwnFieldStringValue("cartofile" ) != null){
				 
			outPutCartofile =  new PrintWriter(new BufferedWriter
					   (new FileWriter(this.getOwnFieldStringValue("cartofile" ))));
			 }
			 if (this.getOwnFieldStringValue("logfile" ) != null){
				  outPutLogFile = new PrintWriter(new BufferedWriter
						   (new FileWriter(this.getOwnFieldStringValue("logfile" ))));
				 
			 }
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		this.memory = new Memory(s);
	}

	
	public int havePenality(Task T) {
		int ref =0;
		double Tpen = Double.parseDouble(this.getOwnFieldStringValue("BurstModeAccesTime"));
		String rwRatio = T.getOwnFieldStringValue("RWratio");
		
		/**
		 * Ajout t?che si inconnus
		 */
		if (this.Tasks.contains(T)){
		
		}
		else{
			this.Tasks.add(T);
			T.setOwnFieldIntValue(this.nameCP+"CacheUsed",0 );
			
			T.setOwnFieldIntValue(this.nameCP+"pSolde",0 );
			T.setOwnFieldIntValue(this.nameCP+"pConsume",0 );
		}
		/**
		 * D?marrage Tache
		 */
		if (T.getET()==0) {
			T.setOwnFieldIntValue(this.nameCP+"CacheUsed",0 );
		}
		/**
		 * Preemption 	
		 */
		if ((this.Last_running != T) && (this.Last_running != null) && (this.Last_running.isEverRunning())) {
						this.Last_running.setOwnFieldStringValue("preempt", "true");
						
				    
			}
		
		/**
		 *  Calcul refilling 
		 */
		if (T.getOwnFieldStringValue("preempt") !=null) {
			if (T.getOwnFieldStringValue("preempt").contentEquals("true")){
				ref = this.calcRefilling(T,this.memory.getUsed(T));
				this.memory.addLine(T, ref,this.Kernel.getTime());
				double penalities = ref* Tpen;
				double crt = Double.parseDouble(T.getOwnFieldStringValue(this.nameCP+"pSolde"));
				T.setOwnFieldStringValue(this.nameCP+"pSolde",(penalities+crt)+"" );
				//System.out.println(T.getId() + "-- " + this.Kernel.getTime() + "  -- " + ref );
			}
		}
		/**
		 * enleve marque preempt 
		 */
		T.setOwnFieldStringValue("preempt", "false");
		/**
		 * Mise ? jour cartographie cache
		 */
	//System.out.println(this.Kernel.getTime()+ "  --  "+ this.getCacheUsed(T) + " -- " + ref );
	 	
			//System.out.println(this.memory.getCarto());
		

		int cNeeded = this.getXi(T);
		int cUsed = this.memory.getUsed(T);
		int cNPred = T.getOwnFieldIntValue(this.nameCP+"CacheUsed");
		int maj =0;
		int newC = 0;
		if (cNeeded <= cUsed ) {
				maj = cNeeded - cNPred ; // quantit? de cache ? mettre ? jour de date
				if (maj < 0 ) maj =0;
		}
		else { 
			if (cNPred <= cUsed ) {
				maj = cUsed - cNPred;
				newC = cNeeded - cUsed;
			}
			else  newC = cNeeded - cNPred;
			if (newC  < 0 ) newC =0; //quantit? de cache manquante ....
		}
 		this.memory.maj(T, maj, this.Kernel.getTime());
 		this.memory.addLine(T, newC , this.Kernel.getTime());
 		
		double penalities = newC* Tpen;
		double crt = Double.parseDouble(T.getOwnFieldStringValue(this.nameCP+"pSolde"));
		T.setOwnFieldStringValue(this.nameCP+"pSolde",(penalities+crt)+"" );
 		
		
		
 		if (T.getId() ==1 )System.out.println(this.Kernel.getTime()+  "  " +   cNeeded + "  " + cUsed  + "   " +   cNPred +"  " + maj + "  "  + newC + "   " + ref );
		
		T.setOwnFieldIntValue(this.nameCP+"CacheUsed", cNeeded);
		/***
		 * Mise ? jour info
		 */
		//T.setOwnFieldIntValue(this.nameCP+"CacheUsed",cacheUsed  );
		this.Last_running = T;
		
		/** 
		 * Est ce qu'on applique penalit?e ....
		 */
		int res =0;
	    crt = Double.parseDouble(T.getOwnFieldStringValue(this.nameCP+"pSolde"));
	    double consume  = Double.parseDouble(T.getOwnFieldStringValue(this.nameCP+"pConsume"));
	    if ((crt - consume) > 1) {
	    	res =1;
	    	T.setOwnFieldStringValue(this.nameCP+"pConsume",(consume+1)+"" );
	    }
		//if (T.getId() ==1 )System.out.println(this.Kernel.getTime()+"   " + newC + "  "  + maj + "  " + ref + "  " + this.memory.getUsed(T));
	    //if (T.getId() ==1 )System.out.println(this.Kernel.getTime()+"  " +  this.getXi(T) );
	return res;
//	    return 0;
	}


	private int getXi(Task T) {
		int Xi = T.getOwnFieldIntValue("Xi");
		int Li = T.getOwnFieldIntValue("Li");
		//if (T.getEET()>0) {
			double  Xta = (Xi/(1.0-Math.exp(-Li*(T.getWCET())/1000.0*this.Kernel.getprecision())  ))*(1.0-Math.exp(-Li*((T.getEET()+1))/1000.0*this.Kernel.getprecision())); 
			return(int)(Xta);
		//}
		//else return 0;
	}

   
	private int calcRefilling(Task T,int cacheUsed) {
		int res =0;
		int Xi = T.getOwnFieldIntValue("Xi");
		int Li = T.getOwnFieldIntValue("Li");
		double  Xt = (Xi/(1.0-Math.exp(-Li*(T.getWCET())/1000.0*this.Kernel.getprecision())  ))*(1.0-Math.exp(-Li*((T.getEET()+1))/1000.0*this.Kernel.getprecision())); ;
		double Xlit = (Xi * T.getEET()+1)  / (T.getWCET());
		double DeltaXi = Xt - Xlit;
		if (DeltaXi <=  cacheUsed ) res =0;
		else res = (int)(DeltaXi - cacheUsed);
		//System.out.println(this.Kernel.getTime()+" -- " + Xt  + "  " + Xlit + "  " + this.memory.getUsed(T));
		//  if (T.getId() ==1 )System.out.println(this.Kernel.getTime()+"  " +  Xt  + "  " +  Xlit +  "  " +DeltaXi );
		return res;
	}

	
}
